/*
 * Copyright 2007 The semap project development team.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Created by dulanov at Dec 29, 2007 6:14:34 AM.
 *
 * $Id: NTriplesWriter.java 858 2007-11-29 09:57:37Z dulanov $
 */

package net.sf.semap.sandbox.rio.ntriples;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;

import org.openrdf.model.BNode;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.RDFWriter;

/**
 * The corrected version of {@link org.openrdf.rio.ntriples.NTriplesWriter} for the UTF-8 support instead US-ASCII.
 *
 * @author <a href="mailto:dulanov@gmail.com">dulanov</a>
 * @version $Id: NTriplesWriter.java 858 2007-11-29 09:57:37Z dulanov $
 */
public class NTriplesWriter implements RDFWriter {

	private Writer writer;
	private boolean writingStarted = false;

	/**
	 * Creates a new NTriplesWriter that will write to the supplied OutputStream.
	 *
	 * @param out The OutputStream to write the N-Triples document to.
	 */
	public NTriplesWriter(OutputStream out) {
		this(new OutputStreamWriter(out, Charset.forName("UTF-8")));
	}

	/**
	 * Creates a new NTriplesWriter that will write to the supplied Writer.
	 *
	 * @param writer The Writer to write the N-Triples document to.
	 */
	public NTriplesWriter(Writer writer) {
		this.writer = writer;
	}

	public RDFFormat getRDFFormat() {
		return RDFFormat.NTRIPLES;
	}

	public void startRDF() throws RDFHandlerException {
		if (writingStarted) {
			throw new RuntimeException("Document writing has already started");
		}
		writingStarted = true;
	}

	public void endRDF() throws RDFHandlerException {
		if (!writingStarted) {
			throw new RuntimeException("Document writing has not yet started");
		}

		try {
			writer.flush();
		} catch (IOException e) {
			throw new RDFHandlerException(e);
		} finally {
			writingStarted = false;
		}
	}

	public void handleNamespace(String prefix, String name) {
		// N-Triples does not support namespace prefixes.
	}

	public void handleStatement(Statement st) throws RDFHandlerException {
		if (!writingStarted) {
			throw new RuntimeException("Document writing has not yet been started");
		}

		Resource subj = st.getSubject();
		URI pred = st.getPredicate();
		Value obj = st.getObject();

		try {
			// SUBJECT
			writeResource(subj);
			writer.write(" ");

			// PREDICATE
			writeURI(pred);
			writer.write(" ");

			// OBJECT
			if (obj instanceof Resource) {
				writeResource((Resource) obj);
			} else if (obj instanceof Literal) {
				writeLiteral((Literal) obj);
			}

			writer.write(" .");
			writeNewLine();
		} catch (IOException e) {
			throw new RDFHandlerException(e);
		}
	}

	public void handleComment(String comment) throws RDFHandlerException {
		try {
			writer.write("# ");
			writer.write(comment);
			writeNewLine();
		} catch (IOException e) {
			throw new RDFHandlerException(e);
		}
	}

	private void writeResource(Resource res) throws IOException {
		if (res instanceof BNode) {
			writeBNode((BNode) res);
		} else {
			writeURI((URI) res);
		}
	}

	private void writeURI(URI uri) throws IOException {
		writer.write(NTriplesUtil.toNTriplesString(uri));
	}

	private void writeBNode(BNode bNode) throws IOException {
		writer.write(NTriplesUtil.toNTriplesString(bNode));
	}

	private void writeLiteral(Literal lit) throws IOException {
		writer.write(NTriplesUtil.toNTriplesString(lit));
	}

	private void writeNewLine() throws IOException {
		writer.write("\n");
	}
}